﻿using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Org.BouncyCastle.Crypto;

namespace TheClerk.Forms.Templates.raw.Envelope
{
    /// <summary>
    /// The container for AssertionCommitment and Proofs
    /// </summary>
    /// <remarks>
    /// EnvelopeContent ::= SEQUENCE {
    /// 	signedData AssertionCommitment,
    ///     proofs Proofs }
    ///     
    /// This class is responsible for using the Chops to sign
    /// the serialized AssertionCommitment.
    /// </remarks>
    internal class EnvelopeContent
    {
        #region Internal members and constructors
        internal AssertionCommitment signedData;
        internal Proofs proofs;
        internal List<AsymmetricIdentity> chopsRequired = new List<AsymmetricIdentity>();
        private List<Chop> chops = new List<Chop>();

        internal EnvelopeContent()
        {
            signedData = new AssertionCommitment();
            proofs = new Proofs();
        }
        #endregion

        internal Stream Serialize()
        {
            // Build the AssertionCommitment so that it can be signed
            byte[] ACder = signedData.ToByteArray();
            // Now, construct the Proofs...
            proofs.SetACContent(ACder);
            // build the inner sequence (Proofs) first
            Stream proofsStream = new System.IO.MemoryStream();
            var dsg = new Org.BouncyCastle.Asn1.DerSequenceGenerator(proofsStream);
            dsg.AddObject(new Org.BouncyCastle.Asn1.DerOctetString(ACder));

            // and serialize it to a byte array
            // byte[] Pder = proofs.ToByteArray();
            dsg.AddObject(proofs.ToAsn1Encodable());
            dsg.Close();
            proofsStream.Position = 0;
            return proofsStream;
        }

        internal byte[] ToByteArray()
        {
            var s = Serialize();
            var buf = new byte[s.Length];
            s.Read(buf, 0, buf.Length);
            return buf;
        }

        internal Chop GetOuterChop()
        {
            return signedData.GetOuterChop();
        }

        internal void AddAssertion(Assertion content)
        {
            signedData.AddAssertion(content);
        }

        internal void AddChop(Chop equipment)
        {
            chops.Add(equipment);
            proofs.AddChop(equipment);
        }

        internal Org.BouncyCastle.Asn1.Asn1Encodable ToAsn1Encodable()
        {
            return Org.BouncyCastle.Asn1.Asn1Object.FromStream(Serialize());
        }
    }
}
